package engine

import (
	"gdfs-center/logcat"
	"net"
	"sync"
)

var engine = &Engine{
	StoreMap: make(map[string]*Storage),
	Index:    0,
	Weight:   0,
}

type Engine struct {
	StoreMap map[string]*Storage //存储服务器
	Index    int64
	Weight   int64
}

//存储服务器
type Storage struct {
	StoreID  string //服务器标识
	NodeID   string //节点ID
	Ip       string //服务器IP
	HttpPort uint64 //http端口
	Mux      sync.RWMutex
	Alive    bool  //是否存活
	Weight   int64 //权重
	Conn     net.Conn
}

//获取引擎
func GetEngine() *Engine {
	return engine
}

////设置是否在线
func (s *Storage) SetAlive(alive bool) {
	s.Mux.Lock()
	s.Alive = alive
	s.Mux.Unlock()
}

//
//判断是否在线
func (s *Storage) IsAlive() (alive bool) {
	s.Mux.RLock()
	alive = s.Alive
	s.Mux.RUnlock()
	return
}

//计算两个数的最大公约数
func countgcd(a, b int64) int64 {
	if b == 0 {
		return a
	}
	return countgcd(b, a%b)
}

//计算多个数的最大公约数
func getGCD(weights []int64) int64 {
	logcat.GetLog().Sugar().Info("###weights.len =", len(weights))
	g := weights[0]
	for i := 1; i < len(weights)-1; i++ {
		oldGcd := g
		g = countgcd(oldGcd, weights[i])
	}
	return g
}

//获取最大权重
func getMaxWeight(weights []int64) int64 {
	var max int64 = 0
	for _, s := range weights {
		if s >= int64(max) {
			max = s
		}
	}
	return max
}

//解绑节点
func UnBindNode(storeid string) {
	if _, ok := engine.StoreMap[storeid]; ok {
		engine.StoreMap[storeid].NodeID = ""
	}
}

//存储服务绑定节点
func BindNode(nodeid, storeid string) {
	if _, ok2 := engine.StoreMap[storeid]; ok2 {
		s := engine.StoreMap[storeid]
		s.NodeID = nodeid
	}
}

//注册服务实例
func RegStoreInstance(s *Storage) {
	//判断storeid是否存在map里面
	if _, ok := engine.StoreMap[s.StoreID]; ok {
		//存在就删除进行更新
		delete(engine.StoreMap, s.StoreID)
	}
	//add
	s.Alive = true
	engine.StoreMap[s.StoreID] = s
	logcat.GetLog().Sugar().Info("###stores数量", len(engine.StoreMap))
}

//获取存储随机权重
func (e *Engine) GetWeightStore() *Storage {
	var weights []int64
	var stores []*Storage
	for _, v := range e.StoreMap {
		weights = append(weights, v.Weight)
		stores = append(stores, v)
	}
	if len(weights) == 0 {
		return &Storage{}
	}
	gcd := getGCD(weights)
	for {
		e.Index = (e.Index + 1) % int64(len(stores))
		if e.Index == 0 {
			e.Weight = e.Weight - gcd
			if e.Weight <= 0 {
				e.Weight = getMaxWeight(weights)
				if e.Weight == 0 {
					return &Storage{}
				}

			}
		}
		if stores[e.Index].Weight >= e.Weight && stores[e.Index].IsAlive() { //获取在线的实例
			return stores[e.Index]
		}
	}
}
